﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;
using mVu.Properties;

namespace mVu
{
  public partial class Form1 : Form
  {
#if PocketPC
    private readonly Microsoft.WindowsCE.Forms.InputPanel _inputPanel1;
#endif

    private Site _site;

    public string SelectedSite { get; set; }
    public string SelectedCategory { get; set; }
    public string SelectedSort { get; set; }
    public string SelectedMedia { get; set; }
    public string Keyword { get; set; }

    private readonly List<string> _siteList;
    private Dictionary<string, string> _categoryList;
    private Dictionary<string, string> _sortList;
    private Dictionary<string, string> _mediaList;
    private readonly List<Thumbnail> _playList;
    private readonly ContextMenu _listviewContextMenu;
    private string _lastSaveDirectory;

    private Thread _thumbnailThread;

    static public string AssemblyDirectory
    {
      get
      {
        var codeBase = System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase;
        var uri = new Uri(codeBase);
        var path = Uri.UnescapeDataString(uri.LocalPath);
        return Path.GetDirectoryName(path);
      }
    }

    public Form1()
    {
      InitializeComponent();

      try
      {
        _lastSaveDirectory = String.Empty;
        _listviewContextMenu = new ContextMenu();
        _playList = new List<Thumbnail>();
        _mediaList = new Dictionary<string, string>();
        _sortList = new Dictionary<string, string>();
        _categoryList = new Dictionary<string, string>();
        _siteList = new List<string>();

        Closing += new System.ComponentModel.CancelEventHandler(Form1_Closing);

        listView1.ItemActivate += new EventHandler(ListView1ItemActivate);
        listView1.View = View.LargeIcon;
        listView1.Columns.Add("Title", -2, HorizontalAlignment.Left);

        tabPage1.GotFocus += new EventHandler(TabPage1GotFocus);
        tabPage2.GotFocus += new EventHandler(TabPage2GotFocus);

#if PocketPC
        _inputPanel1 = new Microsoft.WindowsCE.Forms.InputPanel();
        _inputPanel1.EnabledChanged += new EventHandler(InputPanel1EnabledChanged);
#endif

        keywordTextBox.GotFocus += new EventHandler(TextBox1GotFocus);
        keywordTextBox.LostFocus += new EventHandler(TextBox1LostFocus);

        form1BindingSource.DataSource = this;

        AddSites();

        categoryComboBox.SelectedValueChanged += new EventHandler(CategoryComboBoxSelectedValueChanged);

        SelectedSite = String.Empty;
        SelectedCategory = String.Empty;
        SelectedSort = String.Empty;
        Keyword = String.Empty;

        InitListViewContextMenu();

        versionLabel.Text = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    private void InitListViewContextMenu()
    {
      try
      {
        var mi = new MenuItem { Text = "Play" };
        mi.Click += new EventHandler(MiPlayClick);
        _listviewContextMenu.MenuItems.Add(mi);
        mi = new MenuItem { Text = "Save" };
        mi.Click += new EventHandler(MiSaveClick);
        _listviewContextMenu.MenuItems.Add(mi);
        mi = new MenuItem { Text = "-" };
        _listviewContextMenu.MenuItems.Add(mi);
        mi = new MenuItem { Text = "Add to playlist" };
        mi.Click += new EventHandler(MiAddToPlaylistClick);
        _listviewContextMenu.MenuItems.Add(mi);
        mi = new MenuItem { Text = "Clear playlist" };
        mi.Click += new EventHandler(MiClearPlaylistClick);
        _listviewContextMenu.MenuItems.Add(mi);
        mi = new MenuItem { Text = "Launch playlist" };
        mi.Click += new EventHandler(MiLaunchPlaylistClick);
        _listviewContextMenu.MenuItems.Add(mi);
        mi = new MenuItem { Text = "-" };
        _listviewContextMenu.MenuItems.Add(mi);
        mi = new MenuItem { Text = "Add to queue" };
        mi.Click += new EventHandler(MiAddToQueueClick);
        _listviewContextMenu.MenuItems.Add(mi);
        listView1.ContextMenu = _listviewContextMenu;
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    private void AddSites()
    {
      _siteList.Add(String.Empty);
      _siteList.Add("YouTube");
      _siteList.Add("Pornhub");
      _siteList.Add("RedTube");
      _siteList.Add("Tnaflix");
      _siteList.Add("Tube8");
      // _siteList.Add("YouPorn");
      _siteList.Add("xHamster"); 
      _siteList.Add("Xvideos");
      _siteList.Add("YouJizz");

      siteComboBox.DataSource = _siteList;
      siteComboBox.SelectedValueChanged += new EventHandler(SiteComboBoxSelectedValueChanged);
    }

    void MiPlayClick(object sender, EventArgs e)
    {
      Play();
    }

    void MiSaveClick(object sender, EventArgs e)
    {
      try
      {
        if (Save(true))
        {
          tabControl1.SelectedIndex = 2;
        }
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    void MiAddToPlaylistClick(object sender, EventArgs e)
    {
      try
      {
        if (listView1.FocusedItem != null)
        {
          Cursor.Current = Cursors.WaitCursor;
          var dictionary = _site.GetVideoPaths(listView1.FocusedItem.SubItems[2].Text);
          Cursor.Current = Cursors.Default;

          if (dictionary.ContainsKey(SelectedMedia))
          {
            var t = (Thumbnail)listView1.FocusedItem.Tag;
            t.Url = dictionary[SelectedMedia];
            _playList.Add(t);
          }
        }
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    void MiLaunchPlaylistClick(object sender, EventArgs e)
    {
      try
      {
        var fileName = String.Format("{0}\\mvu.m3u", AssemblyDirectory);
        using (var file = File.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
        {
          using (var sw = new StreamWriter(file))
          {
            foreach (var thumbnail in _playList)
            {
              sw.WriteLine(thumbnail.Url);
            }
          }
        }

        Process.Start(fileName, String.Empty);
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }

    }

    void MiClearPlaylistClick(object sender, EventArgs e)
    {
      _playList.Clear();
    }

    void MiAddToQueueClick(object sender, EventArgs e)
    {
      try
      {
        Save(false);
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
    {
      try
      {
        var isActive = (downloadPanel.Controls.Cast<Control>().Select(c => c as DownloadItem)).Any(di => di != null && di.IsDownloading && !di.IsPaused);

        if (isActive)
        {
          MessageBox.Show("There is a download in progress.  Please cancel the download before closing the application.", Resources.AppName, MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
          tabControl1.SelectedIndex = 2;
          e.Cancel = true;
        }

        if (_thumbnailThread != null)
        {
          _thumbnailThread.Abort();
        }
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    void TabPage1GotFocus(object sender, EventArgs e)
    {
      try
      {
        siteComboBox.Focus();
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    void TabPage2GotFocus(object sender, EventArgs e)
    {
      try
      {
        listView1.Focus();
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    void SiteComboBoxSelectedValueChanged(object sender, EventArgs e)
    {
      try
      {
        switch (siteComboBox.SelectedValue.ToString())
        {
          case "Pornhub":
            _site = new Pornhub();
            break;

          case "RedTube":
            _site = new RedTube();
            break;

          case "Tnaflix":
            _site = new Tnaflix();
            break;

          case "Tube8":
            _site = new Tube8();
            break;

          case "YouPorn":
            _site = new YouPorn();
            break;

          case "xHamster":
            _site = new xHamster();
            break;

          case "Xvideos":
            _site = new Xvideos();
            break;

          case "YouJizz":
            _site = new YouJizz();
            break;

          case "YouTube":
            _site = new YouTube();
            break;

          default:
            _site = null;
            break;
        }

        if (_site != null)
        {
          Cursor.Current = Cursors.WaitCursor;
          _categoryList = _site.GetCategories();
          _sortList = _site.GetSorts();
          _mediaList = _site.GetMediaTypes();
          Cursor.Current = Cursors.Default;

          categoryComboBox.DataSource = new BindingSource(_categoryList, null);
          categoryComboBox.DisplayMember = "Key";
          categoryComboBox.ValueMember = "Value";

          sortComboBox.DataSource = new BindingSource(_sortList, null);
          sortComboBox.DisplayMember = "Key";
          sortComboBox.ValueMember = "Value";

          mediaComboBox.DataSource = new BindingSource(_mediaList, null);
          mediaComboBox.DisplayMember = "Key";
          mediaComboBox.ValueMember = "Key";
          foreach (var s in _mediaList.Keys)
          {
            SelectedMedia = s;
            break;
          }
        }

      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    static void CategoryComboBoxSelectedValueChanged(object sender, EventArgs e)
    {

    }

    void TextBox1LostFocus(object sender, EventArgs e)
    {
#if PocketPC
      _inputPanel1.Enabled = false;
#endif
    }

    void TextBox1GotFocus(object sender, EventArgs e)
    {
#if PocketPC
      _inputPanel1.Enabled = true;
#endif
    }

    static void InputPanel1EnabledChanged(object sender, EventArgs e)
    {
      //#if PocketPC
      //  // Resize the panel docked to the bottom of the form to be
      //  // the same height as the SIP. This moves other controls also
      //  // docked to the bottom of the form to be above the area covered
      //  // by the SIP.
      //  SuspendLayout();
      //  panel2.Visible = inputPanel1.Enabled;
      //  panel2.Height = inputPanel1.Bounds.Height;
      //  ResumeLayout();
      //#endif
    }

    private void Button1Click(object sender, EventArgs e)
    {
      pageUpDown.Value = 1;
      Search(Convert.ToInt32(pageUpDown.Value));

      if (_site != null)
      {
        tabControl1.SelectedIndex = 1;
        listView1.Focus();
      }
    }

    private void Button2Click(object sender, EventArgs e)
    {
      Play();
    }

    private void Button3Click(object sender, EventArgs e)
    {
      if (Save(true))
      {
        tabControl1.SelectedIndex = 2;
      }
    }

    private void ListView1ItemActivate(object sender, EventArgs e)
    {
      Play();
    }

    private void Search(int page)
    {
      Cursor.Current = Cursors.WaitCursor;

      try
      {
        if (_site != null)
        {
          listView1.Items.Clear();

          var thumbnails = _site.GetThumbnails(SelectedCategory, SelectedSort, Keyword, page);

          // Create two ImageList objects.
          var imageListSmall = new ImageList();
          var imageListLarge = new ImageList();

          if (listView1.LargeImageList != null)
          {
            listView1.LargeImageList.Images.Clear();
          }

          if (listView1.SmallImageList != null)
          {
            listView1.SmallImageList.Images.Clear();
          }

          var rectangle = Screen.PrimaryScreen.Bounds;
          if (rectangle.Width >= 480)
          {
            imageListLarge.ImageSize = new Size(128, 128);
            imageListSmall.ImageSize = new Size(64, 64);
          }
          else
          {
            imageListLarge.ImageSize = new Size(64, 64);
            imageListSmall.ImageSize = new Size(32, 32);
          }

          var count = 0;
          foreach (var thumbnail in thumbnails)
          {
            var lvi = new ListViewItem(String.Format("{0}\n{1}", thumbnail.Title, thumbnail.Length));
            lvi.SubItems.Add(thumbnail.Title);
            lvi.SubItems.Add(thumbnail.Url);
            lvi.SubItems.Add(thumbnail.VideoID);
            lvi.SubItems.Add(thumbnail.Length);
            lvi.Tag = thumbnail;
            lvi.ImageIndex = count++; //  imageListLarge.Images.Count > 0 ? imageListLarge.Images.Count - 1 : 0;
            listView1.Items.Add(lvi);
          }

          //Assign the ImageList objects to the ListView.
          listView1.LargeImageList = imageListLarge;
          listView1.SmallImageList = imageListSmall;

          Cursor.Current = Cursors.Default;

          if (_thumbnailThread != null)
          {
            _thumbnailThread.Abort();
          }

          _thumbnailThread = new Thread(delegate()
                                          {
                                            try
                                            {
                                              this.InvokeIfRequired(() => listView1.LargeImageList.Images.Clear());
                                              this.InvokeIfRequired(() => listView1.SmallImageList.Images.Clear());

                                              foreach (var thumbnail in thumbnails)
                                              {
                                                // Initialize the ImageList objects with bitmaps.
                                                var request = (HttpWebRequest)WebRequest.Create(thumbnail.Image);
                                                request.Proxy = null;
                                                request.UserAgent = "Mozilla/4.0";
                                                request.Timeout = 60000;
                                                request.Credentials = CredentialCache.DefaultCredentials;

                                                using (var response = request.GetResponse())
                                                {
                                                  using (var stream = response.GetResponseStream())
                                                  {
                                                    var img = new Bitmap(stream);

                                                    this.InvokeIfRequired(() => listView1.LargeImageList.Images.Add(img));
                                                    this.InvokeIfRequired(() => listView1.SmallImageList.Images.Add(img));
                                                    this.InvokeIfRequired(() => listView1.Invalidate());
                                                  }
                                                }
                                              }
                                            }
                                            catch (ThreadAbortException)
                                            {
                                            }
                                            catch (Exception ex)
                                            {
                                              this.InvokeIfRequired(() => MessageBox.Show(ex.Message, Resources.AppName, MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1));
                                            }
                                          });

          _thumbnailThread.Start();
        }
        else
        {
          MessageBox.Show("You must select a site to search.", Resources.AppName, MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
        }
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    private void Play()
    {
      Cursor.Current = Cursors.WaitCursor;

      try
      {
        if (listView1.FocusedItem != null)
        {
          var dictionary = _site.GetVideoPaths(listView1.FocusedItem.SubItems[2].Text);

          if (dictionary.ContainsKey(SelectedMedia))
          {
            var url = dictionary[SelectedMedia];

            var playerPath = GetPlayerPath();

            if (!String.IsNullOrEmpty(playerPath))
            {
              var psi = new ProcessStartInfo
                          {
                            FileName = playerPath,
                            Arguments = url
                          };
              var process = new Process
                              {
                                StartInfo = psi
                              };
              process.Start();
            }
            else
            {
              MessageBox.Show("Could not find video player.", Resources.AppName, MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
            }
          }
          else
          {
            ShowAvailableFormatsMessage(dictionary);
          }
        }
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }

      Cursor.Current = Cursors.Default;
    }

    private bool Save(bool startDownload)
    {
      try
      {
        if (listView1.FocusedItem != null)
        {
          Cursor.Current = Cursors.WaitCursor;
          var dictionary = _site.GetVideoPaths(listView1.FocusedItem.SubItems[2].Text);
          Cursor.Current = Cursors.Default;

          if (dictionary.ContainsKey(SelectedMedia))
          {
            var url = dictionary[SelectedMedia];

            var sfd = new SaveFileDialog();
            sfd.InitialDirectory = _lastSaveDirectory;
            sfd.FileName = String.Format("{0}", listView1.FocusedItem.SubItems[1].Text);
            var invalidChars = new[] { '\\', '/', ':', '*', '?', '\'', '<', '>', '|' };
            foreach (var c in invalidChars)
            {
              sfd.FileName = sfd.FileName.Replace(c, '_');
            }

            sfd.Filter = String.Format("{0}(*.{0})|*.{0}|All files (*.*)|*.*", _mediaList[SelectedMedia].ToLower());

#if PocketPC
            if (sfd.ShowDialog() == DialogResult.OK)
#endif
            {
              _lastSaveDirectory = Path.GetDirectoryName(sfd.FileName);

              var di = new DownloadItem
                         {
                           URL = url,
                           FileName = sfd.FileName,
                           Index = downloadPanel.Controls.Count,
                           Dock = DockStyle.Top
                         };

              if (startDownload)
              {
                di.Start();
              }

              var mi = new MenuItem { Text = "Remove" };
              mi.Click += delegate
                            {
                              di.Stop();
                              downloadPanel.Controls.Remove(di);
                            };
              di.ContextMenu = new ContextMenu();
              di.ContextMenu.MenuItems.Add(mi);

              downloadPanel.Controls.Add(di);

              return true;
            }
          }
          else
          {
            ShowAvailableFormatsMessage(dictionary);
          }
        }
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }

      return false;
    }

    private void ShowAvailableFormatsMessage(Dictionary<string, string> dictionary)
    {
      string availableFormats = String.Empty;

      foreach (var format in dictionary.Keys)
      {
        if (!String.IsNullOrEmpty(availableFormats))
        {
          availableFormats += ", ";
        }

        availableFormats += format;
      }

      MessageBox.Show(String.Format("This video is not available in {0} format.  Please try one of the following formats: {1}", SelectedMedia, availableFormats), Resources.AppName, MessageBoxButtons.OK, MessageBoxIcon.Hand, MessageBoxDefaultButton.Button1);
    }

    private string GetPlayerPath()
    {
      var playerPath = String.Empty;

      try
      {
        var showFLV = SelectedMedia == "FLV" ? true : false;

        // TODO: Support all the possible formats (i.e. MP4, etc.)
        var rk = Registry.ClassesRoot.OpenSubKey(String.Format("{0}\\Shell\\Open\\Command", showFLV ? "FLVFILE" : "3gpfile"));

        if (rk != null)
        {
          playerPath = rk.GetValue(String.Empty).ToString();
        }

        if (!String.IsNullOrEmpty(playerPath))
        {
          playerPath = playerPath.Replace(" \"%1\"", String.Empty);
        }
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }

      return playerPath;
    }

    private void PageUpDownValueChanged(object sender, EventArgs e)
    {
      try
      {
        Search(Convert.ToInt32(pageUpDown.Value));
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }

    private void DonateLabelClick(object sender, EventArgs e)
    {
      try
      {
        Process.Start("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=K9XS3ZWA76D8A", String.Empty);
      }
      catch (Exception ex)
      {
        Utilities.HandleError(ex);
      }
    }
  }
}